﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Aeon.Configuration;

namespace Aeon.Emulator.Input
{
    /// <summary>
    /// Specifies available input devices for a GamePortConfiguration property.
    /// </summary>
    public sealed class InputDeviceConstraintAttribute : DiscreteDomainConstraintAttribute
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="InputDeviceConstraintAttribute"/> class.
        /// </summary>
        public InputDeviceConstraintAttribute()
        {
        }

        /// <summary>
        /// Returns a collection of the valid domains for the property or field.
        /// </summary>
        /// <param name="member">Property or field to which the constraint applies.</param>
        /// <param name="context">Device configuration instance which contains the property.</param>
        /// <returns>
        /// Collection of the valid domains for the property or field.
        /// </returns>
        public override IEnumerable<object> GetDomains(MemberInfo member, IDeviceConfiguration context)
        {
            if(member == null)
                throw new ArgumentNullException("member");
            if(context == null)
                throw new ArgumentNullException("context");

            var propertyInfo = member as PropertyInfo;
            if(propertyInfo == null)
                throw new ArgumentException("MemberInfo does not describe a property.", "member");
            if(!(context is GamePortConfiguration))
                throw new ArgumentException("Context is not a GamePortConfiguration instance.", "context");
            if(propertyInfo.Name != "ControllerA" && propertyInfo.Name != "ControllerB")
                throw new ArgumentException("This attribute may only be used on a Game Controller property.", "member");

            var controllers = DirectInput.GetInstance().GetDevices(DeviceClass.GameController, DeviceEnumFlags.AttachedOnly).ToList();
            controllers.Insert(0, null);
            
            var currentValue = (DeviceInfo)propertyInfo.GetValue(context, null);
            if(!controllers.Contains(currentValue))
                controllers.Add(currentValue);

            return controllers.AsReadOnly();
        }
    }
}
